[LeetCode-629]K个逆序对数组
题目描述
由 $1-n$ 组成的排列中, 有多少个排列的逆序对个数是 $k$
思路
看完题目和数据范围基本就能确定是动态规划. 因为可行方案可能很多很多, 无法枚举. 而从集合角度1(动态规划)进行计算, 会帮助我们省去很多不必要的枚举. 使用一个数来表示一类有共同点的方案, 是动态规划优化问题的特点.
- 动态规划
- 状态表示:
- $f[i][j]$ : 表示考虑前 $1 - i$ 个数, 且逆序对个数为 $j$ 时的方案数.
- 状态计算:
状态计算的思路是枚举最后一个不同点1: 即考虑将数字i放在什么位置. 放置i位置的可能方式如下:
- 由上图可见, 若将 $i$ 放置在 $i - k$下标处, 这会造成 $k - 1$个逆序对(数 $i$与 下标$\in[i - k + 1, i]$处的数构成逆序对)
- 因此可得: $f[i][j]$ = $\sum_{k=0}^{i - 1} f[i - 1][j - k]$
- 由上分析可见, 状态为$O(n^2)$, 转移为$O(n)$, 总时间复杂度为$O(n^3)$, 会超时.
- 利用前缀和优化状态转移: 记$s[i][j]$ = $\sum_{k=0}^j f[i][k]$, 可得状态计算:
$$ $$
- 状态表示:
Code
1 | const int N = 1010, MOD = 1e9 + 7; |
复杂度分析
- 时间复杂度$O(N * K)$
- 空间复杂度$O(N * K)$
参考资料
- [1] B站yxc
欢迎讨论指正
[LeetCode-629]K个逆序对数组
https://csjsss.github.io/2021/11/11/algo/LeetCode/每日一题/[LeetCode-629]K个逆序对数组/

